import type { CreateImageShapeType } from '@/interface';

interface PropsType {
  container: HTMLDivElement;
  left?: number;
  top?: number;
  width?: number;
  height?: number;
}

interface CreateImageProps {
  src: string;
  width?: number;
  height?: number;
  left?: number;
  top?: number;
}

const disableDrag = (image: HTMLImageElement) => {
  image.addEventListener('dragstart', function (event) {
    event.preventDefault();
  });
};

const createImageBox = (
  imgboxWidth: number,
  imgBoxHeight: number,
  top?: number,
  left?: number
): HTMLDivElement => {
  const imageBox = document.createElement('div');
  imageBox.style.position = 'absolute';
  imageBox.style.top = `${top || 0}px`;
  imageBox.style.left = `${left || 0}px`;
  imageBox.style.width = `${imgboxWidth}px`;
  imageBox.style.height = `${imgBoxHeight}px`;
  imageBox.style.boxShadow = '2px 2px 10px 2px #a7a7a7';
  imageBox.style.transformOrigin = '0 0';
  imageBox.style.transform = 'translate(0, 0)';
  imageBox.style.willChange = 'transform, width, height';
  imageBox.style.userSelect = 'none';
  imageBox.style.resize = 'both';
  imageBox.style.cursor = 'pointer';
  return imageBox;
};

const createImage = (src: string) => {
  const img = document.createElement('img');
  img.style.width = '100%';
  img.style.height = '100%';
  img.style.objectFit = 'cover';
  img.src = src;
  disableDrag(img); // 禁止拖拽
  return img;
};

const createImageBoxDrag = () => {
  const after = document.createElement('div');
  after.className = 'image-box-drag';
  after.style.position = 'absolute';
  after.style.right = '0px';
  after.style.bottom = '0px';
  after.style.width = '10px';
  after.style.height = '10px';
  after.style.backgroundColor = 'transparent';
  after.style.cursor = 'se-resize';
  after.style.zIndex = '1';
  return after;
};

const createImageIcon = ({ src, type }: { src: string; type: string }): HTMLImageElement => {
  const img = document.createElement('img');
  img.src = src;
  img.style.width = '30px';
  img.style.height = '30px';
  img.style.position = 'absolute';
  img.style.top = '0px';
  if (type === 'confirm') {
    img.style.right = `0px`;
    img.style.transform = 'translate(50%, -50%)';
  }
  if (type === 'cancel') {
    img.style.left = `0px`;
    img.style.transform = 'translate(-50%, -50%)';
  }
  disableDrag(img); // 禁止拖拽
  return img;
};

const getPointInsideDrag = (x: number, y: number, el: Element | undefined): boolean => {
  if (!el) {
    return false;
  }
  const rect = el.getBoundingClientRect();
  const left = x - rect.left;
  const top = y - rect.top;
  if (left >= 0 && left <= rect.width && top >= 0 && top <= rect.height) {
    return true;
  }
  return false;
};

class CreateImage implements CreateImageShapeType {
  container: HTMLDivElement;
  imageLeft: number;
  imageTop: number;
  imageWidth: number;
  imageHeight: number;
  constructor(props: PropsType) {
    this.container = props.container;
    this.imageLeft = props.left || 0;
    this.imageTop = props.top || 0;
    this.imageWidth = props.width || 0;
    this.imageHeight = props.height || 0;
  }

  createImage(
    { src, width, height, left, top }: CreateImageProps,
    confirm?: (data: {
      image: HTMLImageElement;
      left: number;
      top: number;
      width: number;
      height: number;
    }) => void,
    cancel?: () => void
  ) {
    const img = createImage(src);
    img.onload = () => {
      const { width: _width, height: _height } = img;
      let imgboxWidth = width || 0;
      let imgBoxHeight = height || 0;

      if (!width && !height) {
        if (_height > this.containerRect.height) {
          imgBoxHeight = this.containerRect.height / 1.2;
          imgboxWidth = (imgBoxHeight / _height) * _width;
        } else {
          imgboxWidth = 400;
          imgBoxHeight = (imgboxWidth / _width) * _height;
        }
      }

      const imageBox = createImageBox(imgboxWidth, imgBoxHeight, top, left);
      const imageBoxDrag = createImageBoxDrag();

      const createUrl = (type: string) => {
        return require(`@/static/${type}.png`);
      };

      const confirmImg = createImageIcon({ src: createUrl('confirm'), type: 'confirm' });
      confirmImg.addEventListener('click', () => {
        this.container.removeChild(imageBox);
        if (confirm) {
          confirm({
            image: img,
            left: this.imageLeft,
            top: this.imageTop,
            width: this.imageWidth,
            height: this.imageHeight,
          });
        }
      });

      const cancelImg = createImageIcon({ src: createUrl('cancel'), type: 'cancel' });
      cancelImg.addEventListener('click', () => {
        this.container.removeChild(imageBox);
        cancel && cancel();
      });

      imageBox.appendChild(img);
      imageBox.appendChild(imageBoxDrag);
      imageBox.appendChild(confirmImg);
      imageBox.appendChild(cancelImg);
      this.container.appendChild(imageBox);
      this.setImageRectByImageBox(imageBox);
      this.registerImageBoxListener(imageBox);
    };

    return img;
  }

  private get containerRect() {
    return this.container.getBoundingClientRect();
  }

  private registerImageBoxListener(imageBox: HTMLDivElement) {
    let moveX = 0;
    let moveY = 0;

    imageBox.onmousedown = (event) => {
      const startX = event.clientX;
      const startY = event.clientY;
      const children = imageBox.children;
      const imageBoxDrag = Array.from(children).find((item) => item.className === 'image-box-drag');
      const isResizing = getPointInsideDrag(startX, startY, imageBoxDrag);

      window.onmousemove = (event) => {
        if (isResizing) {
          const rect = imageBox.getBoundingClientRect();
          const nWidth = Math.max(event.clientX - rect.left, 100);
          const nHeight = (nWidth / rect.width) * rect.height;
          imageBox.style.width = `${nWidth}px`;
          imageBox.style.height = `${nHeight}px`;
        } else {
          const translateX = moveX + event.clientX - startX;
          const translateY = moveY + event.clientY - startY;
          imageBox.style.transform = `translate(${translateX}px , ${translateY}px)`;
        }
        this.setImageRectByImageBox(imageBox);
      };

      window.onmouseup = (event) => {
        if (!isResizing) {
          moveX += event.clientX - startX;
          moveY += event.clientY - startY;
        }
        window.onmousemove = null;
        window.onmouseup = null;
      };
    };
  }

  private setImageRectByImageBox(imageBox: HTMLDivElement) {
    const rect = imageBox.getBoundingClientRect();
    this.imageLeft = rect.left - this.containerRect.left;
    this.imageTop = rect.top - this.containerRect.top;
    this.imageWidth = rect.width;
    this.imageHeight = rect.height;
  }
}

export default CreateImage;
